 (* Creating a structure, which makes use of a list of tuples to make a
    mapping. Performancewise this is bad, but it makes for a simple example. *)

structure Mapping = struct
    exception NotFound;

    val create = nil;

    fun lookup (key, nil) = raise NotFound
      | lookup (key, (existing_key, value)::rest_entries) =
        if key = existing_key
        then value
        else lookup (key, rest_entries);

    fun insert (key, value, nil) = [(key,value)]
      | insert (key, value, (existing_key, existing_value)::rest_entries) =
        if key = existing_key
        then (key, value) :: rest_entries
        else (existing_key, existing_value) :: insert (key, value, rest_entries);
end;

(* restrict use of structure using a signature *)
(* 1: define a signature, which restricts the Mapping structure. The signature
   is "attached to a structure". *)

signature StringIntMapping = sig
    exception NotFound;
    val create : (string * int) list;
    val insert : string * int * (string * int) list -> (string * int) list;
    val lookup : string * (string * int) list -> int;
end;

(* 2: define a new structure, which has the signature and the same name Mapping,
   to shadow the original Mapping. *)

structure SiMapping : StringIntMapping = Mapping;

(* Now we have created a new structure, which only allows mapping from string to
   int. *)
(* We can use this structure as usual, by prefixing with its name and using the
   dot notation. *)

val my_map = SiMapping.create;
val map_with_stuff = SiMapping.insert ("a", 1, my_map);
